#ifndef N1SOCKET_H
#define N1SOCKET_H

#include "N1Include.h"
#include "N1Object.h"
#include "N1Exception.h"
#include "N1Delegate.h"
#include "N1Thread.h"

#ifndef WINDOWS

typedef int SOCKET;

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <netinet/in.h>     /* INADDR_ANY, sockaddr_in ... */
#include <string.h>
#include <errno.h>
#include <unistd.h>

#endif

class N1NetworkAddress;

class N1NerworkException : public N1Exception {
    int32 m_error;
public:
    N1NerworkException() {  };

    int32 getError() { return m_error; };
};

class N1Socket : public N1Object {
    SOCKET _socket;

    bool setBlockMode(bool bBlock);
    bool setReuseAddr(bool bOn);

public:
    N1Socket();
    N1Socket(SOCKET s);
    virtual ~N1Socket();

    virtual pcstr name() const ;

    static N1Socket* udpSocket();

    operator SOCKET() { return _socket; };

    void bind(const char* name, uint16 port);

    void listen(volatile N1Bool *pBreak, N1DelegatePtr<void, N1Socket*> *p); 

    void connect(pcstr addr, uint16 port);

    void send(const void *data, N1UInt32 size);

    void recv(void *buff, N1UInt32 size, N1UInt32 *pReaded);

    void sendto(const void *data, N1UInt32 size, N1NetworkAddress *addr);
    uint32 recvfrom(void *buffer, N1UInt32 size, N1NetworkAddress **addr);
};


class N1NetworkAddress : public N1Object {
public:
    virtual struct sockaddr*  addr()=0;
    virtual uint32            size()=0;
};

class N1NetworkAddressIPv4 : public N1NetworkAddress {
    struct sockaddr_in m_addr;
    uint32 m_error;

    friend class N1Socket;

    N1NetworkAddressIPv4() : m_error(0) {};
public:
    N1NAME_DECL

    N1NetworkAddressIPv4(const char* name, uint16 port);
    virtual ~N1NetworkAddressIPv4()  { };

    virtual struct sockaddr*  addr() { return (struct sockaddr*)&m_addr; };
    virtual uint32            size() { return sizeof(m_addr);            };
};

void N1SocketInitialize();


#endif //N1SOCKET_H
